<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-alpha.63">
<title data-react-helmet="true">6. 数据校验 | Fur</title><meta data-react-helmet="true" name="docsearch:version" content="current,latest"><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="og:title" content="6. 数据校验 | Fur"><meta data-react-helmet="true" name="description" content="6.1 关于数据校验"><meta data-react-helmet="true" property="og:description" content="6.1 关于数据校验"><meta data-react-helmet="true" property="og:url" content="https://furos.cn/docs/data-validation"><link data-react-helmet="true" rel="shortcut icon" href="/img/favicon.ico"><link data-react-helmet="true" rel="canonical" href="https://furos.cn/docs/data-validation"><link rel="stylesheet" href="/styles.83aacb78.css">
<link rel="preload" href="/styles.16c5981f.js" as="script">
<link rel="preload" href="/runtime~main.e25f3aa1.js" as="script">
<link rel="preload" href="/main.b54c8f62.js" as="script">
<link rel="preload" href="/1.0b36cbc2.js" as="script">
<link rel="preload" href="/2.17909aba.js" as="script">
<link rel="preload" href="/3.f42eda22.js" as="script">
<link rel="preload" href="/1be78505.c23a6c85.js" as="script">
<link rel="preload" href="/31.92e96840.js" as="script">
<link rel="preload" href="/f976f453.bd53d64a.js" as="script">
<link rel="preload" href="/17896441.c3d5fc96.js" as="script">
<link rel="preload" href="/17256d0f.a583c10e.js" as="script">
</head>
<body>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<nav class="navbar navbar--light navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><div aria-label="Navigation bar toggle" class="navbar__toggle" role="button" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></div><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs/">Next</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs">文档</a><a class="navbar__item navbar__link" href="/blog">博客</a><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">配置</a></div><div class="navbar__items navbar__items--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">视频</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">工具</a><ul class="dropdown__menu"><li><a target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">代码生成器</a></li></ul></div><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">看板</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">仓库</a><ul class="dropdown__menu"><li><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">Gitee</a></li><li><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">GitHub</a></li></ul></div><div class="react-toggle react-toggle--disabled displayOnlyInLargeViewport_2aTZ"><div class="react-toggle-track"><div class="react-toggle-track-check"><span class="toggle_BsTx">🌜</span></div><div class="react-toggle-track-x"><span class="toggle_BsTx">🌞</span></div></div><div class="react-toggle-thumb"></div><input type="checkbox" disabled="" aria-label="Dark mode toggle" class="react-toggle-screenreader-only"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div><div class="navbar-sidebar"><div class="navbar-sidebar__brand"><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a></div><div class="navbar-sidebar__items"><div class="menu"><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">Versions</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link navbar__link--active" href="/docs">文档</a></li><li class="menu__list-item"><a class="menu__link" href="/blog">博客</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">配置</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">视频</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">工具</a><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link" position="left">代码生成器</a></li></ul></li><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="menu__link">看板</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">仓库</a><ul class="menu__list"><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">Gitee</a></li><li class="menu__list-item"><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">GitHub</a></li></ul></li></ul></div></div></div></nav><div class="main-wrapper"><div class="docPage_2gpo"><div class="docSidebarContainer_3_JD" role="complementary"><div class="sidebar_2urC"><div class="menu menu--responsive menu_5FrY"><button aria-label="Open Menu" aria-haspopup="true" class="button button--secondary button--sm menu__button" type="button"><svg aria-label="Menu" class="sidebarMenuIcon_Dm3K" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 32 32" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><ul class="menu__list"><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">1. 框架介绍</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/">1.1 介绍</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/author">1.2 关于作者</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">2. 配置与选项</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/configuration">2.1 配置</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/options">2.2 选项</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/dynamic-api-controller">3. 动态 WebAPI</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/specification-document">4. 规范化接口文档</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/friendly-exception">5. 友好异常处理</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link menu__link--active active" href="/docs/data-validation">6. 数据校验</a></li></ul></div></div></div><main class="docMainContainer_3EyW"><div class="container padding-vert--lg docItemWrapper_1EkI"><div class="row"><div class="col docItemCol_2ASc"><div class="docItemContainer_3QWW"><article><header><h1 class="docTitle_1Lrw">6. 数据校验</h1></header><div class="markdown"><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="61-关于数据校验"></a>6.1 关于数据校验<a aria-hidden="true" tabindex="-1" class="hash-link" href="#61-关于数据校验" title="Direct link to heading">#</a></h2><p>数据校验字面上的意思就是对使用者提交过来的数据进行合法性验证。在一套完善的应用系统中，数据有效性校验是必不可少的业务处理第一道关卡。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="62-数据校验的好处"></a>6.2 数据校验的好处<a aria-hidden="true" tabindex="-1" class="hash-link" href="#62-数据校验的好处" title="Direct link to heading">#</a></h2><ul><li>过滤不安全数据，提高系统的安全性</li><li>减少不必要的业务异常处理，提高系统的响应速度</li><li>大大提高系统稳定性</li><li>大数据并发时起着一定的缓冲作用</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="63-数据校验方式"></a>6.3 数据校验方式<a aria-hidden="true" tabindex="-1" class="hash-link" href="#63-数据校验方式" title="Direct link to heading">#</a></h2><ul><li>传统方式，在业务代码之前手动验证</li><li><code>Mvc</code> 特性方式，<code>Mvc</code> 内置的 <code>DataAnnotations</code> 方式</li><li><strong>推荐方式</strong>，<code>Fur</code> 框架内置的 <code>DataValidation</code> 验证</li><li>其他方式，使用第三方验证库，如 <code>FluentValidation</code></li></ul><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="631-传统方式"></a>6.3.1 传统方式<a aria-hidden="true" tabindex="-1" class="hash-link" href="#631-传统方式" title="Direct link to heading">#</a></h3><p>在很多老项目中，我们经常看到这样的代码：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">public bool Insert(Person person)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    // 验证参数</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    if(string.IsNullOrEmty(person.Name))</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        throw new System.Exception(&quot;名字不能为空&quot;);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    if(person.Age &lt; 18)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        throw new System.Exception(&quot;年龄不能小于 18 岁&quot;);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    if(!person.Password.Equals(person.ConfirmPassword)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        throw new System.Exception(&quot;两次密码不一致&quot;);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    // 业务代码</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    _repository.Insert(person.Adapt&lt;PersonEntity&gt;());</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    // ...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>从上面的代码看起来，似乎没有什么不妥，但是从一个程序可维护性来说，这是一个糟糕的代码，因为该业务代码中<strong>包含了太多与业务无关的数据验证</strong>。</p><p>试想一下，如果这个 <code>Person</code> 有 几十个参数都需要验证呢？可想而知，这是一个庞大的业务代码。</p><p>再者，如果其他地方也需要用到这个 <code>Person</code> 类验证呢？那代码好比老鼠啃过的面包屑一样，到处都是。</p><p>如此得知，这样的方式是极其不推荐的，<strong>不但污染了业务代码，也破坏了业务职责单一性原理，也让验证逻辑无法实现通用，后续维护难度大大升级</strong>。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="632-mvc-特性方式"></a>6.3.2 <code>Mvc</code> 特性方式<a aria-hidden="true" tabindex="-1" class="hash-link" href="#632-mvc-特性方式" title="Direct link to heading">#</a></h3><p>在 <code>ASP.NET Core</code> 中，微软为我们提供了全新的 <code>特性</code> 验证方式，可通过对对象贴特性实现数据验证。这种方式有效的将数据校验和业务代码剥离开来，而且容易使用和拓展。</p><ul><li><strong>在模型中验证</strong></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using System.ComponentModel.DataAnnotations;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Hoa.Application.Authorization.Dtos</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class SignInInput</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Required]  // 必填验证</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [MinLength(4)]  // 最小长度验证</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Account { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Required]    // 必填验证</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [MaxLength(32)]    // 最大长度验证</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Password { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><ul><li><strong>在参数中验证</strong></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">public void CheckMethodParameterValid(</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [Required]    // 必填验证</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [MinLength(4)]    // 最小长度验证</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    string name,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    int age,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [Required]    // 必填验证</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [RegularExpression(&quot;[a-zA-Z0-9_]{8,30}&quot;)    // 正则表达式验证</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    string password,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [Required]    // 必填验证</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [RegularExpression(&quot;[a-zA-Z0-9_]{8,30}&quot;)    // 正则表达式验证</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    string confirmPassword</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    // TODO</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>小提醒</h5></div><div class="admonition-content"><p>如果函数的参数大于或等于 3 个，建议抽离出模型类，也就是不建议上面的方式。</p></div></div><ul><li><strong>自定义特性验证</strong></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">public class ClassicMovieAttribute : ValidationAttribute</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public ClassicMovieAttribute(int year)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        Year = year;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public int Year { get; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string GetErrorMessage() =&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        $&quot;Classic movies must have a release year no later than {Year}.&quot;;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    protected override ValidationResult IsValid(object value, ValidationContext validationContext)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        var movie = (Movie)validationContext.ObjectInstance;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        var releaseYear = ((DateTime)value).Year;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        if (movie.Genre == Genre.Classic &amp;&amp; releaseYear &gt; Year)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            return new ValidationResult(GetErrorMessage());</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        return ValidationResult.Success;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><ul><li><strong><code>IValidatableObject</code> 复杂验证</strong></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using System.Collections.Generic;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">public class DtoModel : IValidatableObject</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [Required]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [StringLength(100)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string Title { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    // 你的验证逻辑</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public IEnumerable&lt;ValidationResult&gt; Validate(ValidationContext validationContext)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        if (你的逻辑代码)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            yield return new ValidationResult(</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                &quot;错误消息&quot;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                ,new[] { nameof(Title) }  // 验证失败的属性</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            );</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p><code>Mvc</code> 特性方式极大的将业务逻辑和验证进行了剥离和解耦，而且还能实现自定义复杂验证。</p><p><strong>但是 <code>Mvc</code> 特性验证方式有几个明显的缺点</strong>：</p><ul><li>只能在 <code>控制器</code> 中的 <code>Action</code>（动作方法）中使用</li><li><strong>无法在任意类、任意方法中使用</strong></li><li>内置的验证类型非常有效，且不易拓展</li><li>不支持验证消息后期配置</li></ul><p>所以，<code>Fur</code> 提供了新的验证引擎 <code>DataValidation</code>，在完全兼容 <code>Mvc</code> 内置验证的同时提供了大量常见验证、复杂验证、自定义验证等能力。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="64-datavalidation-验证-"></a>6.4 <code>DataValidation</code> 验证 🤗<a aria-hidden="true" tabindex="-1" class="hash-link" href="#64-datavalidation-验证-" title="Direct link to heading">#</a></h2><p><code>DataValidation</code> 是 <code>Fur</code> 框架提供了全新的验证方式，完全兼容 <code>Mvc</code> 内置验证，并且赋予了超能。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="641-datavalidation-优点"></a>6.4.1 <code>DataValidation</code> 优点<a aria-hidden="true" tabindex="-1" class="hash-link" href="#641-datavalidation-优点" title="Direct link to heading">#</a></h3><ul><li><strong>完全兼容 <code>Mvc</code> 内置验证引擎</strong></li><li><strong>内置常见验证类型及可自定义验证类型功能</strong></li><li>提供全局对象拓展验证方式</li><li>支持验证消息后期配置，支持实时更新</li><li>支持在任何类，任何方法、任何位置实现手动验证、特性方式验证等</li><li>支持设置验证结果模型</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="65-datavalidation-使用"></a>6.5 <code>DataValidation</code> 使用<a aria-hidden="true" tabindex="-1" class="hash-link" href="#65-datavalidation-使用" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="651-注册验证服务"></a>6.5.1 注册验证服务<a aria-hidden="true" tabindex="-1" class="hash-link" href="#651-注册验证服务" title="Direct link to heading">#</a></h3><div class="mdxCodeBlock_1XEh"><div style="color:#bfc7d5;background-color:#292d3e" class="codeBlockTitle_3nn1">Fur.Web.Entry/Startup.cs</div><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd undefined">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC codeBlockWithTitle_3QsD"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Builder;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Hosting;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class Startup</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // Other Codes...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public void ConfigureServices(IServiceCollection services)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            services.AddApp();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            services.AddControllers()</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                    .AddDataValidation();    // 可通过 .AddDataValidation(false) 关闭全局验证处理</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            // Other Codes...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="admonition admonition-important alert alert--info"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>特别注意</h5></div><div class="admonition-content"><p><code>.AddDataValidation()</code> 需在 <code>services.AddControllers()</code> 之后注册。同时 <code>services.AddApp()</code> 总是最先注册。</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="652-兼容-mvc-特性验证"></a>6.5.2 兼容 <code>Mvc</code> 特性验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#652-兼容-mvc-特性验证" title="Direct link to heading">#</a></h3><div><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_1w39 tabs__item--active" style="outline:none">TestDto</li><li role="tab" tabindex="0" aria-selected="false" class="tabs__item tabItem_1w39" style="outline:none">FurAppService</li></ul><div role="tabpanel" class="margin-vert--md"><div><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using System.ComponentModel.DataAnnotations;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class TestDto</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Range(10, 20, ErrorMessage = &quot;Id 只能在 10-20 区间取值&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public int Id { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Required(ErrorMessage = &quot;必填&quot;), MinLength(3, ErrorMessage = &quot;字符串长度不能少于3位&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div></div></div></div><p>如下图所示：</p><img src="/img/sjyz1.gif"><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="653-兼容-mvc-复杂验证"></a>6.5.3 兼容 <code>Mvc</code> 复杂验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#653-兼容-mvc-复杂验证" title="Direct link to heading">#</a></h3><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using System.Collections.Generic;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using System.ComponentModel.DataAnnotations;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class TestDto : IValidatableObject</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [Range(10, 20, ErrorMessage = &quot;Id 只能在 10-20 区间取值&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public int Id { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [Required(ErrorMessage = &quot;必填&quot;), MinLength(3, ErrorMessage = &quot;字符串长度不能少于3位&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public IEnumerable&lt;ValidationResult&gt; Validate(ValidationContext validationContext)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            if (Name.StartsWith(&quot;Fur&quot;))</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                yield return new ValidationResult(</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                    &quot;不能以 Fur 开头&quot;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                    , new[] { nameof(Name) }</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                );</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>如下图所示：</p><img src="/img/sjyz2.gif"><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="66-手动验证"></a>6.6 手动验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#66-手动验证" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="661-验证模型"></a>6.6.1 验证模型<a aria-hidden="true" tabindex="-1" class="hash-link" href="#661-验证模型" title="Direct link to heading">#</a></h3><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Fur.DataValidation;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DynamicApiController;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class FurAppService : IDynamicApiController</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [NonValidation] // 跳过全局验证</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public DataValidationResult Post(TestDto testDto)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            return testDto.TryValidate();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>如下图所示：</p><img src="/img/sjyz3.gif"><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</h5></div><div class="admonition-content"><p>支持 <strong><code>Mvc</code></strong> 内置的特性验证、属性验证及复杂的 <strong><code>IValidatableObject</code></strong> 验证。</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="662-validationtypes-常见验证"></a>6.6.2 <code>ValidationTypes</code> 常见验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#662-validationtypes-常见验证" title="Direct link to heading">#</a></h3><p><code>Fur</code> 内置了很多常用类型的数据验证，包括：</p><ul><li><code>Required</code>：非空、非 Null 类型</li><li><code>Numeric</code>：数值类型</li><li><code>PositiveNumber</code>：正数类型</li><li><code>NegativeNumber</code>：负数类型</li><li><code>Integer</code>：整数类型</li><li><code>Money</code>：金钱类型</li><li><code>Date</code>：日期类型</li><li><code>Time</code>：时间类型</li><li><code>IDCard</code>：身份证类型</li><li><code>PostCode</code>：邮编类型</li><li><code>PhoneNumber</code>：手机号类型</li><li><code>Telephone</code>：固话类型</li><li><code>PhoneOrTelNumber</code>：手机或固话类型</li><li><code>EmailAddress</code>：邮件地址类型</li><li><code>Url</code>：网址类型</li><li><code>Color</code>：颜色值类型</li><li><code>Chinese</code>：中文类型</li><li><code>IPv4</code>：IPv4 地址类型</li><li><code>IPv6</code>：IPv6 地址类型</li><li><code>Age</code>：年龄类型</li><li><code>ChineseName</code>：中文名类型</li><li><code>EnglishName</code>：英文名类型</li><li><code>Capital</code>：纯大写英文类型</li><li><code>Lowercase</code>：纯小写英文类型</li><li><code>Ascii</code>：Ascii 类型</li><li><code>Md5</code>：Md5 字符串类型</li><li><code>Zip</code>：压缩包格式类型</li><li><code>Image</code>：图片格式类型</li><li><code>Document</code>：文档格式类型</li><li><code>MP3</code>：Mp3 格式类型</li><li><code>Flash</code>：Flash 格式类型</li><li><code>Video</code>：视频文件格式类型</li></ul><p><strong>使用示例</strong></p><div><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_1w39 tabs__item--active" style="outline:none">单个类型验证</li><li role="tab" tabindex="0" aria-selected="false" class="tabs__item tabItem_1w39" style="outline:none">多个组合类型验证</li></ul><div role="tabpanel" class="margin-vert--md"><div><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 验证必填</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">&quot;&quot;.TryValidate(ValidationTypes.Required);   // =&gt; false</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 验证中文</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">&quot;我叫 MonK&quot;.TryValidate(ValidationTypes.Chinese); // =&gt; false</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 验证数值</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">2.TryValidate(ValidationTypes.Numeric); // =&gt; true</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 验证整数</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">true.TryValidate(ValidationTypes.Integer); // =&gt; false</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 验证邮箱</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">&quot;monksoul@outlook.com&quot;.TryValidate(ValidationTypes.EmailAddress); // =&gt; true</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 验证负数</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">2.0m.TryValidate(ValidationTypes.NegativeNumber); // =&gt; false</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 自定义正则表达式验证</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">&quot;Fur&quot;.TryValidate(&quot;/^Fur$&quot;); // =&gt; true</span></div></div></div></div></div></div></div></div><div class="admonition admonition-tip alert alert--success"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>小知识</h5></div><div class="admonition-content"><p>可通过设置 <code>TryValidate([ValidationOptions], params object[] validationTypes)</code> 方法的 <code>ValidationOptions</code> 参数配置验证逻辑，如：<strong><code>同时成立</code></strong> 或 <strong><code>只要一个成立</code></strong> 即可验证通过</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="663-datavalidation-特性"></a>6.6.3 <code>[DataValidation]</code> 特性<a aria-hidden="true" tabindex="-1" class="hash-link" href="#663-datavalidation-特性" title="Direct link to heading">#</a></h3><p><code>Fur</code> 还提供了 <code>[DataValidation]</code> 特性方便在模型参数中使用 <code>ValidationTypes</code> 常见验证或自定义验证。</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Fur.DataValidation;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class TestDto</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [DataValidation(ValidationTypes.Integer)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public int Id { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [DataValidation(ValidationTypes.Numeric, ValidationTypes.Integer)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public int Cost { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [DataValidation(ValidationOptions.AtLeastOne, ValidationTypes.Chinese, ValidationTypes.Date)]</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // 可以和Mvc特性共存</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Required, DataValidation(ValidationTypes.Age)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public int Age { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [DataValidation(ValidationTypes.IDCard, ErrorMessage = &quot;自定义身份证提示消息&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string IDCard { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="67-nonvalidation-跳过验证"></a>6.7 <code>[NonValidation]</code> 跳过验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#67-nonvalidation-跳过验证" title="Direct link to heading">#</a></h2><p><code>Fur</code> 框架提供了对象模型跳过验证特性 <code>[NonValidation]</code>，支持在 <code>控制器</code>，<code>动作方法</code>，<code>类</code> 中使用。</p><p>一旦贴了此特性，那么将不会执行验证操作。</p><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</h5></div><div class="admonition-content"><p><strong><code>[NonValidation]</code></strong> 只对对象类型有效，值类型无效。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="68-高级自定义操作"></a>6.8 高级自定义操作<a aria-hidden="true" tabindex="-1" class="hash-link" href="#68-高级自定义操作" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="681-自定义-validationtypes-类型"></a>6.8.1 自定义 <code>ValidationTypes</code> 类型<a aria-hidden="true" tabindex="-1" class="hash-link" href="#681-自定义-validationtypes-类型" title="Direct link to heading">#</a></h3><p>除了 <code>Fur</code> 内置的验证类型以外，<code>Fur</code> 还提供了非常灵活的自定义验证类型机制。</p><p>实现自定义验证类型必须遵循以下配置：</p><ul><li>验证类型必须时公开且时 <code>Enum</code> 枚举类型</li><li>枚举类型必须贴有 <code>[ValidationType]</code> 特性</li><li>枚举中每一项必须贴有 <code>[ValidationItemMetadata]</code> 特性</li></ul><p><strong>如</strong>：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Fur.DataValidation;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using System.Text.RegularExpressions;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [ValidationType]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public enum MyValidationTypes</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// 强密码类型</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;/summary&gt;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [ValidationItemMetadata(@&quot;^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$&quot;, &quot;必须须包含大小写字母和数字的组合，不能使用特殊字符，长度在8-10之间&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        StrongPassword,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// 以 Fur 字符串开头，忽略大小写</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;/summary&gt;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [ValidationItemMetadata(@&quot;^(fur).*&quot;, &quot;默认提示：必须以Fur字符串开头，忽略大小写&quot;, RegexOptions.IgnoreCase)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        StartWithFurString</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div></div></div></div></div><p><strong>使用</strong></p><ul><li>手动使用</li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">&quot;q1w2e3&quot;.TryValidate(MyValidationTypes.StrongPassword); // =&gt; false</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">&quot;furos&quot;.TryValidate(MyValidationTypes.StartWithFurString); // =&gt; true</span></div></div></div></div></div><ul><li><code>[DataValidation]</code> 中使用</li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">[DataValidation(MyValidationTypes.StrongPassword)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">public string Password { get; set; }</span></div></div></div></div></div><ul><li>多个自定义类型混用</li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">&quot;Q1w2e3r4t5!*&quot;.TryValidate(MyValidationTypes.StrongPassword, ValidationTypes.Required); // =&gt; true</span></div></div></div></div></div><div class="admonition admonition-caution alert alert--warning"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>特别注意</h5></div><div class="admonition-content"><p>自定义的验证类型也要保证名称全局唯一，也就是多个验证类型不能出现一样的名字。</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="682-自定义-validationtypes-失败消息"></a>6.8.2 自定义 <code>ValidationTypes</code> 失败消息<a aria-hidden="true" tabindex="-1" class="hash-link" href="#682-自定义-validationtypes-失败消息" title="Direct link to heading">#</a></h3><p><code>Fur</code> 内置的 <code>ValidationTypes</code> 已有默认的失败消息：</p><ul><li><code>Required</code>：<strong>The Value is required.</strong></li><li><code>Numeric</code>：<strong>The Value is not a numeric type.</strong></li><li><code>PositiveNumber</code>：<strong>The Value is not a positive number type.</strong></li><li><code>NegativeNumber</code>：<strong>The Value is not a negative number type.</strong></li><li><code>Integer</code>：<strong>The Value is not a integer type.</strong></li><li><code>Money</code>：<strong>The Value is not a money type.</strong></li><li><code>Date</code>：<strong>The Value is not a date type.</strong></li><li><code>Time</code>：<strong>The Value is not a time type.</strong></li><li><code>IDCard</code>：<strong>The Value is not a idcard type.</strong></li><li><code>PostCode</code>：<strong>The Value is not a postcode type.</strong></li><li><code>PhoneNumber</code>：<strong>The Value is not a phone number type.</strong></li><li><code>Telephone</code>：<strong>The Value is not a telephone type.</strong></li><li><code>PhoneOrTelNumber</code>：<strong>The Value is not a phone number or telephone type.</strong></li><li><code>EmailAddress</code>：<strong>The Value is not a email address type.</strong></li><li><code>Url</code>：<strong>The Value is not a url address type.</strong></li><li><code>Color</code>：<strong>The Value is not a color type.</strong></li><li><code>Chinese</code>：<strong>The Value is not a chinese type.</strong></li><li><code>IPv4</code>：<strong>The Value is not a IPv4 type.</strong></li><li><code>IPv6</code>：<strong>The Value is not a IPv6 type.</strong></li><li><code>Age</code>：<strong>The Value is not a age type.</strong></li><li><code>ChineseName</code>：<strong>The Value is not a chinese name type.</strong></li><li><code>EnglishName</code>：<strong>The Value is not a english name type.</strong></li><li><code>Capital</code>：<strong>The Value is not a capital type.</strong></li><li><code>Lowercase</code>：<strong>The Value is not a lowercase type.</strong></li><li><code>Ascii</code>：<strong>The Value is not a ascii type.</strong></li><li><code>Md5</code>：<strong>The Value is not a md5 type.</strong></li><li><code>Zip</code>：<strong>The Value is not a zip type.</strong></li><li><code>Image</code>：<strong>The Value is not a image type.</strong></li><li><code>Document</code>：<strong>The Value is not a document type.</strong></li><li><code>MP3</code>：<strong>The Value is not a mp3 type.</strong></li><li><code>Flash</code>：<strong>The Value is not a flash type.</strong></li><li><code>Video</code>：<strong>The Value is not a video type.</strong></li></ul><p>我们可以通过创建继承 <code>IValidationMessageTypeProvider</code> 验证消息提供器类型，或通过 <code>appsettings.json</code> 配置。</p><ul><li><strong><code>[ValidationMessageType]</code></strong> 方式</li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DataValidation;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [ValidationMessageType]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public enum MyValidationMessageType</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // 修改内置验证类型验证失败消息</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [ValidationMessage(&quot;值不能为空或Null&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        Required,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [ValidationMessage(&quot;必须是数值类型&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        Numeric,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [ValidationMessage(&quot;必须是正数&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        PositiveNumber,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // 修改自定义类型验证失败消息</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [ValidationMessage(&quot;密码太简单了&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        StrongPassword,</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [ValidationMessage(&quot;必须以 Fur 开头&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        StartWithFurString</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="admonition admonition-tip alert alert--success"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>小知识</h5></div><div class="admonition-content"><p>除了贴 <code>[ValidationMessageType]</code> 特性外，<code>Fur</code> 框架还提供了 <code>IValidationMessageTypeProvider</code> 方式查找验证消息类型，如下图所示：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Fur.DataValidation;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using System;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class MyValidationTypeMessageProvider : IValidationMessageTypeProvider</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public Type[] Definitions =&gt; new[]</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            typeof(MyValidationMessageType),</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            typeof(MyValidationMessageType2)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        };</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>注册验证消息提供器</p><div class="mdxCodeBlock_1XEh"><div style="color:#bfc7d5;background-color:#292d3e" class="codeBlockTitle_3nn1">Fur.Web.Entry/Startup.cs</div><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd undefined">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC codeBlockWithTitle_3QsD"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Builder;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Hosting;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class Startup</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // Other Codes...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public void ConfigureServices(IServiceCollection services)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            services.AddApp();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            services.AddControllers()</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                    .AddDataValidation&lt;MyValidationTypeMessageProvider&gt;();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            // Other Codes...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div></div></div><p>如下图所示：</p><img src="/img/sjyz4.png"><ul><li><strong><code>appsettings.json</code> 方式</strong></li></ul><div class="mdxCodeBlock_1XEh"><div style="color:#bfc7d5;background-color:#292d3e" class="codeBlockTitle_3nn1">Fur.Web.Entry/appsettings.json</div><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd undefined">Copy</button><div tabindex="0" class="prism-code language-json codeBlock_3iAC codeBlockWithTitle_3QsD"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">&quot;AppSettings&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">&quot;ValidationTypeMessageSettings&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">&quot;Definitions&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Required&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;值不能为空或Null&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Numeric&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;必须是数值类型&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">&quot;StrongPassword&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;密码太简单了!!!&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></div></div></div></div><div class="admonition admonition-important alert alert--info"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>important</h5></div><div class="admonition-content"><p><code>appsettings.json</code> 中相同的 <code>Key</code> 或覆盖 <code>IValidationMessageTypeProvider</code> 提供相同 <code>Key</code> 的值。</p></div></div><h4><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="错误消息查找优先级"></a>错误消息查找优先级<a aria-hidden="true" tabindex="-1" class="hash-link" href="#错误消息查找优先级" title="Direct link to heading">#</a></h4><p><code>DefaultErrorMessage</code> -&gt; <code>IValidationMessageTypeProvider</code> -&gt; <code>appsettings.json</code> (<strong>低 -&gt; 高</strong>)</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="69-模型验证范围"></a>6.9 模型验证范围<a aria-hidden="true" tabindex="-1" class="hash-link" href="#69-模型验证范围" title="Direct link to heading">#</a></h2><p><code>Fur</code> 提供多种模型验证范围设置：</p><ul><li>全局验证（默认）</li><li><code>[NonValidation]</code> 跳过验证</li><li><code>[TypeFilter(typeof(DataValidationFilter))]</code> 局部验证</li><li><code>[ApiController]</code> 控制器范围验证</li></ul><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="691-全局验证"></a>6.9.1 全局验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#691-全局验证" title="Direct link to heading">#</a></h3><p>默认情况下，通过 <code>.AddDataValidation()</code> 注册数据验证服务已经启用了全局验证，如若不想启用全局验证，则传入 <code>false</code> 即可，如：<code>.AddDataValidation(false)</code>。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="692-nonvalidation-跳过验证"></a>6.9.2 <code>[NonValidation]</code> 跳过验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#692-nonvalidation-跳过验证" title="Direct link to heading">#</a></h3><p>可通过 <code>[NonValidation]</code> 贴在 <code>控制器</code>，<code>动作方法</code>，<code>类</code> 中跳过全局验证或不需要验证</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="693-typefiltertypeofdatavalidationfilter-局部验证"></a>6.9.3 <code>[TypeFilter(typeof(DataValidationFilter))]</code> 局部验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#693-typefiltertypeofdatavalidationfilter-局部验证" title="Direct link to heading">#</a></h3><p>我们也可以无需注册 <code>.AddDataValidation()</code> 服务，直接在 <code>动作方法</code> 上贴 <code>[TypeFilter(typeof(DataValidationFilter))]</code> 可启用局部验证。如：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Fur.DataValidation;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DynamicApiController;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Mvc;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class FurAppService : IDynamicApiController</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [TypeFilter(typeof(DataValidationFilter))]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public TestDto Post(TestDto testDto)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return testDto;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="694-apicontroller-控制器范围验证"></a>6.9.4 <code>[ApiController]</code> 控制器范围验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#694-apicontroller-控制器范围验证" title="Direct link to heading">#</a></h3><p><code>[ApiController]</code> 是 <code>Mvc</code> 提供的控制器范围（含所有动作方法）的验证。</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Mvc;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry.Controllers</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [ApiController]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class MvcController : Controller</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public IActionResult Index()</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return View();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="610-miniprofiler-查看"></a>6.10 <code>MiniProfiler</code> 查看<a aria-hidden="true" tabindex="-1" class="hash-link" href="#610-miniprofiler-查看" title="Direct link to heading">#</a></h2><p>如下图所示：</p><img src="/img/sjyz5.png"><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="610-多语言支持"></a>6.10 多语言支持<a aria-hidden="true" tabindex="-1" class="hash-link" href="#610-多语言支持" title="Direct link to heading">#</a></h2><p>文档整理中...</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="611-验证模型提供器"></a>6.11 验证模型提供器<a aria-hidden="true" tabindex="-1" class="hash-link" href="#611-验证模型提供器" title="Direct link to heading">#</a></h2><p>文档整理中...</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="612-反馈与建议"></a>6.12 反馈与建议<a aria-hidden="true" tabindex="-1" class="hash-link" href="#612-反馈与建议" title="Direct link to heading">#</a></h2><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>与我们交流</h5></div><div class="admonition-content"><p>给 Fur 提 <a href="https://gitee.com/monksoul/Fur/issues/new?issue" target="_blank" rel="noopener noreferrer">Issue</a>。</p></div></div></div></article><div class="margin-vert--xl"><div class="row"><div class="col"><a href="https://gitee.com/monksoul/Fur/tree/alpha/docs/docs/data-validation.mdx" target="_blank" rel="noreferrer noopener"><svg fill="currentColor" height="1.2em" width="1.2em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 40 40" style="margin-right:0.3em;vertical-align:sub"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div></div></div><div class="margin-vert--lg"><nav class="pagination-nav" aria-label="Blog list page navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/docs/friendly-exception"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« 5. 友好异常处理</div></a></div><div class="pagination-nav__item pagination-nav__item--next"></div></nav></div></div></div><div class="col col--3"><div class="tableOfContents_3SO_"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#61-关于数据校验" class="table-of-contents__link">6.1 关于数据校验</a></li><li><a href="#62-数据校验的好处" class="table-of-contents__link">6.2 数据校验的好处</a></li><li><a href="#63-数据校验方式" class="table-of-contents__link">6.3 数据校验方式</a><ul><li><a href="#631-传统方式" class="table-of-contents__link">6.3.1 传统方式</a></li><li><a href="#632-mvc-特性方式" class="table-of-contents__link">6.3.2 <code>Mvc</code> 特性方式</a></li></ul></li><li><a href="#64-datavalidation-验证-" class="table-of-contents__link">6.4 <code>DataValidation</code> 验证 🤗</a><ul><li><a href="#641-datavalidation-优点" class="table-of-contents__link">6.4.1 <code>DataValidation</code> 优点</a></li></ul></li><li><a href="#65-datavalidation-使用" class="table-of-contents__link">6.5 <code>DataValidation</code> 使用</a><ul><li><a href="#651-注册验证服务" class="table-of-contents__link">6.5.1 注册验证服务</a></li><li><a href="#652-兼容-mvc-特性验证" class="table-of-contents__link">6.5.2 兼容 <code>Mvc</code> 特性验证</a></li><li><a href="#653-兼容-mvc-复杂验证" class="table-of-contents__link">6.5.3 兼容 <code>Mvc</code> 复杂验证</a></li></ul></li><li><a href="#66-手动验证" class="table-of-contents__link">6.6 手动验证</a><ul><li><a href="#661-验证模型" class="table-of-contents__link">6.6.1 验证模型</a></li><li><a href="#662-validationtypes-常见验证" class="table-of-contents__link">6.6.2 <code>ValidationTypes</code> 常见验证</a></li><li><a href="#663-datavalidation-特性" class="table-of-contents__link">6.6.3 <code>[DataValidation]</code> 特性</a></li></ul></li><li><a href="#67-nonvalidation-跳过验证" class="table-of-contents__link">6.7 <code>[NonValidation]</code> 跳过验证</a></li><li><a href="#68-高级自定义操作" class="table-of-contents__link">6.8 高级自定义操作</a><ul><li><a href="#681-自定义-validationtypes-类型" class="table-of-contents__link">6.8.1 自定义 <code>ValidationTypes</code> 类型</a></li><li><a href="#682-自定义-validationtypes-失败消息" class="table-of-contents__link">6.8.2 自定义 <code>ValidationTypes</code> 失败消息</a></li></ul></li><li><a href="#69-模型验证范围" class="table-of-contents__link">6.9 模型验证范围</a><ul><li><a href="#691-全局验证" class="table-of-contents__link">6.9.1 全局验证</a></li><li><a href="#692-nonvalidation-跳过验证" class="table-of-contents__link">6.9.2 <code>[NonValidation]</code> 跳过验证</a></li><li><a href="#693-typefiltertypeofdatavalidationfilter-局部验证" class="table-of-contents__link">6.9.3 <code>[TypeFilter(typeof(DataValidationFilter))]</code> 局部验证</a></li><li><a href="#694-apicontroller-控制器范围验证" class="table-of-contents__link">6.9.4 <code>[ApiController]</code> 控制器范围验证</a></li></ul></li><li><a href="#610-miniprofiler-查看" class="table-of-contents__link">6.10 <code>MiniProfiler</code> 查看</a></li><li><a href="#610-多语言支持" class="table-of-contents__link">6.10 多语言支持</a></li><li><a href="#611-验证模型提供器" class="table-of-contents__link">6.11 验证模型提供器</a></li><li><a href="#612-反馈与建议" class="table-of-contents__link">6.12 反馈与建议</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container"><div class="row footer__links"><div class="col footer__col"><h4 class="footer__title">文档</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/docs">入门</a></li><li class="footer__item"><a class="footer__link-item" href="/docs">指南</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">社区</h4><ul class="footer__items"><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">讨论</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="footer__link-item">看板</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">更多</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/blog">博客</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="footer__link-item">仓库</a></li></ul></div></div><div class="text--center"><div>Copyright © 2020 Fur, Baiqian Co.,Ltd.</div></div></div></footer></div>
<script src="/styles.16c5981f.js"></script>
<script src="/runtime~main.e25f3aa1.js"></script>
<script src="/main.b54c8f62.js"></script>
<script src="/1.0b36cbc2.js"></script>
<script src="/2.17909aba.js"></script>
<script src="/3.f42eda22.js"></script>
<script src="/1be78505.c23a6c85.js"></script>
<script src="/31.92e96840.js"></script>
<script src="/f976f453.bd53d64a.js"></script>
<script src="/17896441.c3d5fc96.js"></script>
<script src="/17256d0f.a583c10e.js"></script>
</body>
</html>